package com.me.study.javaCore.nio;

import org.junit.Test;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousFileChannel;
import java.nio.channels.CompletionHandler;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.concurrent.Future;

/**
 * AsynchronousFileChannel：异步读写文件
 */
public class AsynchronousFileChannelTests {

    private static final int CAPACITY = 1024;

    @Test
    public void readAsync() throws IOException {
        AsynchronousFileChannel fileChannel = AsynchronousFileChannel.open(Paths.get("target/../target/classes/test-file.txt"), StandardOpenOption.READ);
        ByteBuffer buffer = ByteBuffer.allocate(CAPACITY);

        readAllAsync(fileChannel, buffer, 0);
    }

    private void readAllAsync(AsynchronousFileChannel fileChannel, ByteBuffer buffer, long offset) {
        // 读完文件，或者读满 buffer都算完成。
        fileChannel.read(buffer, offset, buffer, new CompletionHandler<Integer, ByteBuffer>() {
            @Override
            public void completed(Integer length, ByteBuffer attachment) {
                // System.out.println(redStr("result = " + length));
                // System.out.println(redStr("attachment = " + attachment.hasRemaining()));
                if (length == -1) {
                    try {
                        fileChannel.close();
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                    return;
                }

                attachment.flip();
                byte[] data = new byte[attachment.limit()];
                attachment.get(data);
                System.out.print(new String(data));
                attachment.clear();

                readAllAsync(fileChannel, buffer, offset + CAPACITY);
            }

            @Override
            public void failed(Throwable exc, ByteBuffer attachment) {
                exc.printStackTrace();
            }
        });
    }

    private String redStr(String str) {
        return "\33[31;4m" + str + "\33[0m";
    }

    @Test
    public void writeAsync() throws IOException {
        byte[] srcBytes = "[2020/10/22 00:00:01][DEBUG] [054351217190]\n[invoice_access_token1]38_bQLY8Y1zF7QlwIc9N7XxQIV39yO-X1".getBytes(StandardCharsets.UTF_8);
        Path path = Paths.get("target/classes/test-file.txt");

        if(!Files.exists(path)){
            Files.createFile(path);
        }

        try (AsynchronousFileChannel fileChannel = AsynchronousFileChannel.open(path, StandardOpenOption.WRITE)) {
            ByteBuffer buffer = ByteBuffer.allocate(srcBytes.length);
            long position = 0;

            buffer.put(srcBytes);
            buffer.flip();

            fileChannel.write(buffer, position, buffer, new CompletionHandler<Integer, ByteBuffer>() {
                @Override
                public void completed(Integer length, ByteBuffer attachment) {
                    System.out.println(redStr("bytes written: " + length));
                }

                @Override
                public void failed(Throwable exc, ByteBuffer attachment) {
                    exc.printStackTrace();
                }
            });
        }
    }

    @Test
    public void readAsync2() throws IOException {
        ByteBuffer buffer;
        Future<Integer> operation;
        try (AsynchronousFileChannel fileChannel = AsynchronousFileChannel.open(Paths.get("target/../target/classes/test-file.txt"), StandardOpenOption.READ)) {
            buffer = ByteBuffer.allocate(CAPACITY);
            long position = 0;

            operation = fileChannel.read(buffer, position);
            while (!operation.isDone());

            buffer.flip();
            byte[] data = new byte[buffer.limit()];
            buffer.get(data);
            System.out.println(new String(data));
            buffer.clear();
        }
    }

}
